using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;
using System.IO;
using System.Reflection;
using System.Text;
using System.Data.SqlClient;
using System.Text.RegularExpressions;
using System.Net.Mail;
using System.Security.Principal;

using Humans = PHSRAG.Insight21.Humans;
using Policy = PHSRAG.Insight21.Policy;
using Utility = PHSRAG.Utility;
using InsightUtilities = PHSRAG.Insight21.InsightUtilities;
using PHSRAG.Insight21.Humans;
using IDSIS = InsightWebService.IDSIS;
using Forms = PHSRAG.Insight21.FormsManagement;
using PHSRAG.SharePointUtility;
using log4net;
using InsightServiceUtility = InsightWebService.InsightServiceUtility;
using PHSRAG.Security;
namespace PHSRAG.InsightWebService
{
	/// <summary>
	/// The Humans class within the PHSRAG.InsightWebService namespace wraps any calls
	/// to Humans objects that outside systems (in this case, the Protocol Feed) need to 
	/// call methods on Humans objects. Currently, we only need a Humans webservice, but 
	/// going forward, we will add other modules as needed within their own ASMX webservice file.
	/// </summary>
	[WebService(Namespace = "http://www.partners.org/webservices/PHSRAG/Humans/")]
	[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
	public class Humans : System.Web.Services.WebService
	{
		private static readonly ILog log = LogManager.GetLogger(typeof(Humans));

		private Forms.QuestionnaireAnswer studyPop = null;
		private Forms.QuestionnaireAnswer performanceSites = null;
		private Forms.QuestionnaireAnswer ancillary = null;

		private const int InactiveOverallStatus = 2;
		private const int IRBWithdrawnSubStatus = 11;

		public Humans()
		{
			InitializeComponent();
		}

		#region Component Designer generated code

		//Required by the Web Services Designer 
		private IContainer components = null;

		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose(bool disposing)
		{
			if (disposing && components != null)
			{
				components.Dispose();
			}
			base.Dispose(disposing);
		}

		#endregion

		[WebMethod]
		[SoapDocumentMethod(OneWay = true)]
		public void RegistereIRBUser(string insightConnStr, int sProtocolId)
		{
			try
			{
				/*Registers user within Insight
				 * Gives the user access to Humans module
				 * Sends email to Inight helpdesk to register this user in PAS             
				 */
				SqlConnection conn = new SqlConnection(insightConnStr);
				SqlDataReader rdr = Utility.DataAccess.ExecuteReader(
					insightConnStr,
					"dbo.RegisterStudyStaff",
					Utility.DataAccess.BuildSqlParameterArray("@protocolId", SqlDbType.Int, sProtocolId));

				/*email helpdesk with the delimited usernames*/
				if (rdr.Read())
				{
					string users = rdr["usernames"].ToString();
					if (users.Length > 0)
					{
						SendEmail(
							ConfigurationManager.AppSettings["Email.From"]
							, ConfigurationManager.AppSettings["Email.HelpDesk"]
							, ConfigurationManager.AppSettings["Email.Subject.RegistereIRBUser"]
							, "PAS Registration Required. Users: " + users);
					}

				}
			}
			catch (Exception ex)
			{
				string body = "RegisterIRBUser Failed -  " + sProtocolId.ToString() + "." + ex.Message;
				SendEmail(
					ConfigurationManager.AppSettings["Email.From"]
					, ConfigurationManager.AppSettings["Email.ToError"]
					, ConfigurationManager.AppSettings["Email.Subject.RegistereIRBUser"] + ": Failed",
					body);
			}

		}

		private void SendEmail(string sFrom, string sTo, string sSubject, string sBody)
		{

			try
			{
				MailMessage mailMessage = new MailMessage(sFrom, sTo, sSubject, sBody);
				SmtpClient client = new SmtpClient(ConfigurationManager.AppSettings["Email.SMTPServer"]);
				client.Send(mailMessage);
			}
			catch
			{
				throw;
			}
		}

		/// <summary>
		/// MoveProcessToRex inserts or updates a process in Rex with the appropriate data from Insight.
		/// If no protocolprocess with that ID, the webservice throws an exception that no process
		/// exists for that ID. Also, the webservice throws an exception if some other error is encountered.
		/// </summary>
		/// <param name="insightConnectionString">the Insight connection string</param>
		/// <param name="rexConnectionString">the Rex connection string</param>
		/// <param name="processId">the process to be moved.</param>
		[WebMethod]
		public string MoveProcessToRex(string insightConnectionString, string rexConnectionString, int processId)
		{
			try
			{
                log.InfoFormat("Moving process {0} to Rex.", processId);
				Policy.ICachePolicy cachePolicy = new Policy.ApplicationCachePolicy(Application);

				System.Data.DataTable roles = PHSRAG.Insight21.Humans.StudyStaff.GetHumansStudyRoles(insightConnectionString);

				cachePolicy.Cache(InsightUtilities.Constants.HumansRolesKey, roles);

				cachePolicy.Cache(InsightUtilities.Constants.HumansRolesKey,
					Application[InsightUtilities.Constants.HumansRolesKey]);

				PHSRAG.Insight21.Humans.ProtocolProcess process = PHSRAG.Insight21.Humans.ProtocolProcess.GetProtocolProcess(
					insightConnectionString,
					processId,
					cachePolicy,
					null);

				if (process != null)
				{
					DirectoryInfo directoryInfo = new DirectoryInfo(System.IO.Path.GetDirectoryName(
						(new Regex(@"^file:/+")).Replace(Assembly.GetExecutingAssembly().CodeBase, string.Empty)));

					PHSRAG.Insight21.Humans.RexParams rexParameters = null;
					if (process.Protocol.ModuleType == PHSRAG.Insight21.Humans.Constants.ModuleType.Humans)
						rexParameters = new PHSRAG.Insight21.Humans.RexParams();
					else if (process.Protocol.ModuleType == PHSRAG.Insight21.Humans.Constants.ModuleType.Animals)
						rexParameters = new PHSRAG.Insight21.Humans.AnimalsRexParams();

					process.Submit(cachePolicy, insightConnectionString,
						rexConnectionString, string.Format("{0}\\", directoryInfo.FullName), rexParameters, false);

                    log.Info("Process submitted.");

                    /*DM changes. 
                     * When the protocol number is got from ReX, the metadata information on 
                    the SharePoint site needs to be updated for the protocol
                     * */
                    try
                    {
                        UpdateProtcolMetaData(process);
                    }
                    catch
                    {
                        //email notifictaion would be ideal
                    }
                    /*Trackit 10114: Delete frozen documents on an MoveProcessToRex */
                    try
                    {
                        WindowsImpersonationContext wic = Authenticator.ImpersonateUser(
                  Utility.Settings.GetKeyValue("ServiceAcount", "rag29"),
                  Utility.Settings.GetKeyValue("ServiceAcountPwd", "z0hcq"),
                  Authenticator.LogonType.NewCredentials, Authenticator.LogonProvider.WinNT50);

                        InsightServiceUtility.DocumentUtility docUtil = new InsightServiceUtility.DocumentUtility();
                        docUtil.DeleteViewAppDocuments(processId, process.ProtocolId);
                        Authenticator.RevertUser(wic);
                    }
                    catch (Exception ex)
                    {
                        SendEmail(
                      ConfigurationManager.AppSettings["Email.From"]
                      , ConfigurationManager.AppSettings["Email.ToError"]
                      ,string.Format("App delete failed on move to rex for Process Id: {0}",processId),
                      ex.StackTrace );
                    }
				}
				else
				{
					return string.Format("No process with ID: {0} exists.", processId);
				}
			}
			catch (Exception ex)
			{
				string result = string.Format("Process Id: {0} has failure: {1}", processId, ex.Message);
				if (ex.InnerException != null)
					result = string.Format("{0} {1}", result, ex.InnerException.Message);

                log.Error(result, ex);
				Utility.ExceptionReport.WriteToEventLog(String.Format("ProtocolProcess {0} failed Moving to Rex.", processId.ToString()),
					ex, true, Utility.ExceptionReport.ReportType.Error);

				return result;
			}

			return "Success";
		}


        private void UpdateProtcolMetaData( ProtocolProcess process)
        {
            try
            {

                string folderHierarchy = CreateFolderHierarchy(process, false, string.Empty);
                Hashtable metadata = new Hashtable();
                metadata.Add("ProtocolNumber",process.Protocol.ProtocolNumber);
                metadata.Add("ProtocolTitle", process.Protocol.Title);
                DocumentLibrary documentLibrary = new DocumentLibrary();
                documentLibrary.UpdateMetadata(folderHierarchy, metadata);
            }
            catch(Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog(String.Format("ProtocolProcess {0} failed update metadata.", process.Id.ToString()),
                    ex, true, Utility.ExceptionReport.ReportType.Error);
            }
        }

        /// <summary>
        /// Create the url for sharepoint
        /// </summary>
        /// <param name="protocolId"></param>
        /// <param name="docId"></param>
        /// <returns></returns>
        private string CreateFolderHierarchy(ProtocolProcess process, bool isViewAppDocument, string appType)
        {

            string folderHierarchy = string.Empty;
            string moduleName = process.Protocol.ModuleType == "H" ? "Humans" : "Animals";
            string url = Utility.Settings.GetKeyValue("SharePointBlobURL", string.Empty);
            string docLibName = Utility.Settings.GetKeyValue("DocLibName", "Document");
            if (string.IsNullOrEmpty(process.Protocol.ProtocolNumber ))
            {
                url += "/" + moduleName + "/" + DateTime.Now.Year + "/" + docLibName;
            }
            else
            {
                url += "/" + moduleName + "/" + process.Protocol.ProtocolNumber.ToString().Substring(0, 4) + "/" + docLibName;
            }
            folderHierarchy = url + "/" + process.Protocol.Id;

            if (isViewAppDocument)
            {
                folderHierarchy += "/" + appType + "/" + process.Id + "_" + "Application.Pdf";
            }
            return folderHierarchy;
        }

		/// <summary>
		/// the ApproveProcess method loads a ProtocolProcess with the passed-in ID and 
		/// calls the Approve method on the Protocol Process (see that method for details
		/// of what it does). If no protocolProcess exists with that ID, the webservice
		/// throws an exception that no process exists for that Id. Also this throws an 
		/// exception if some type of error is encountered.
		/// </summary>
		/// <param name="insightConnectionString">Connectionstring to the Insight database</param>
		/// <param name="rexConnectionString">COnnection to the corresponding Rex database</param>
		/// <param name="processId">The Identity value of the ProtocolProcess to be Approved.</param>
		[WebMethod]
		public string ApproveProcess(string insightConnectionString, string rexConnectionString, int processId)
		{
            log.InfoFormat("Approving process {0}.", processId);
			ProtocolProcess process = ProtocolProcess.GetProtocolProcess(
						insightConnectionString,
						processId,
						new Policy.NullCachePolicy(),
						null);

			PHSRAG.Insight21.Policy.ICachePolicy cachePolicy = new Policy.NullCachePolicy();
			Protocol protocol = new PHSRAG.Insight21.Humans.Protocol(cachePolicy);
			protocol.Load(insightConnectionString, process.ProtocolId);

			if (process != null)
			{
				SqlConnection insightConnection = new SqlConnection(insightConnectionString);
				SqlConnection rexConnection = new SqlConnection(rexConnectionString);

				SqlTransaction insightTransaction = null;
				SqlTransaction rexTransaction = null;
				try
				{
					rexConnection.Open();
					rexTransaction = rexConnection.BeginTransaction();

					insightConnection.Open();
					insightTransaction = insightConnection.BeginTransaction();

					// preload before Approving. 
					foreach (ProtocolVersion version in process.ProtocolVersions)
					{
						int count = version.QuestionnaireAnswers.Count;
					}

					foreach (ProtocolProcess someProcess in protocol.ProtocolProcesses)
					{
						foreach (ProtocolVersion someVersion in someProcess.ProtocolVersions)
						{
							int count = someVersion.QuestionnaireAnswers.Count;
						}
					}

                    bool isLegacy = protocol.IsLegacy;
                    
                    process.Approve(insightTransaction,
									rexTransaction,
									insightConnectionString,
									rexConnectionString,
									protocol);

					process.Save(insightTransaction);

					insightTransaction.Commit();
					rexTransaction.Commit();
                    log.Info("Process approved.");
					ProtocolVersion latestIRVersion = Protocol.GetLatestApplicationVersion(
							process.ProtocolId,
							insightConnectionString,
							false,
							cachePolicy);

					if (latestIRVersion != null)
					{
						ProtocolProcess IR =
							ProtocolProcess.GetProtocolProcess(
							insightConnectionString,
							latestIRVersion.ProtocolProcessId,
							cachePolicy,
							null);

						// Now get the latest IR process and submit it.
						DirectoryInfo directoryInfo = new DirectoryInfo(System.IO.Path.GetDirectoryName(
							(new Regex(@"^file:/+")).Replace(Assembly.GetExecutingAssembly().CodeBase, string.Empty)));

						RexParams rexParameters = new RexParams();

						if (process.Type == Constants.ProtocolProcessType.Amendment)
						{
                            log.Info("Submitting updated humans IR based on Amendment.");
							IR.Submit(new Policy.NullCachePolicy(), insightConnectionString,
								rexConnectionString, string.Format("{0}\\", directoryInfo.FullName), rexParameters, false);
                           
						}
						else if (process.Type == Constants.AnimalProtocolProcessType.Amendment)
                        {
                            log.Info("Submitting updated animals IR based on Amendment.");
                            rexParameters = new AnimalsRexParams();
                            // We use the IsAmendment field to change the way the number of 
                            // animals is calculated in Rex.  If this IR was created as new
                            // because it used to be a legacy, the number of animals is the total,
                            // not additional, so set IsAmendment to false for previously legacy 
                            // protocols.
                            ((AnimalsRexParams)rexParameters).IsAmendment = true && !isLegacy;
                            IR.Submit(new Policy.NullCachePolicy(), insightConnectionString,
                                rexConnectionString, string.Format("{0}\\", directoryInfo.FullName), rexParameters, false);
                        }
                        else if (process.Type == Constants.AnimalProtocolProcessType.TriennialReview)
						{
                            log.Info("Submitting updated animals IR based on Triennial Review.");
                            rexParameters = new AnimalsRexParams();
                            IR.Submit(new Policy.NullCachePolicy(), insightConnectionString,
								rexConnectionString, string.Format("{0}\\", directoryInfo.FullName), rexParameters, false);
						}
					}

					else
					{

						// if the ID isn't zero, look it up to see if
						// what we have is the current attachmentTitle # (in case it's
						// been cloned in Rex bc of Amendment or Correction)
						if (protocol.RexProtocolId != 0)
						{
							//int currentRexProtId = Convert.ToInt32(Utility.DataAccess.ExecuteScalar(rexConnectionString,
							//    "spIRBRetrieveCurrentProtocolId",
							//    Utility.DataAccess.BuildSqlParameterArray(
							//    "@sFolderNumber", SqlDbType.VarChar, protocol.ProtocolNumber)));

							protocol.RexProtocolId = process.GetCurrentRexProtocolId(rexConnectionString
																					, rexTransaction
																					, protocol.ProtocolNumber,
																					(protocol.ModuleType.Equals("H")) ? Constants.ModuleType.Humans : Constants.ModuleType.Animals);
						}

						protocol.StudyStaffList = null;
						int count = protocol.StudyStaffList.Count;


						// Legacy protocols must update the data in Rex??
						if (process.Type == Constants.ProtocolProcessType.Amendment ||
							process.Type == Constants.AnimalProtocolProcessType.Amendment)
						{
							protocol.UpdateTitleVersionInRex(rexConnection, rexTransaction);
							protocol.UpdateStaffInREX(insightConnectionString, rexConnectionString);

						}

					}

					if (process.Type == Constants.ProtocolProcessType.Amendment
						|| process.Type == Constants.ProtocolProcessType.InitialReview)
					{
						// See if we have any information to send to the IDSIS team
						if (ConfigurationManager.AppSettings["EnableIDSISWebServiceCalls"].ToLower() == "true")
						{
							ProtocolVersion version = Protocol.GetLatestApplicationVersion(process.ProtocolId, Utility.DataAccess.ConnectionString, false, cachePolicy);
							PushToIDSIS(protocol, version);
						}
					}
                    /*Trackit 10114: Delete frozen documents on an approval */
                    try
                    {
                        WindowsImpersonationContext wic = Authenticator.ImpersonateUser(
                         Utility.Settings.GetKeyValue("ServiceAccount", "rag29"),
                         Utility.Settings.GetKeyValue("ServiceAccountPwd", "z0hcq"),
                         Authenticator.LogonType.NewCredentials, Authenticator.LogonProvider.WinNT50);


                        InsightServiceUtility.DocumentUtility docUtil = new InsightServiceUtility.DocumentUtility();
                        docUtil.DeleteViewAppDocuments(processId, process.ProtocolId);
                        Authenticator.RevertUser(wic);
                    }
                    catch (Exception ex)
                    {
                        SendEmail(
                      ConfigurationManager.AppSettings["Email.From"]
                      , ConfigurationManager.AppSettings["Email.ToError"]
                      , string.Format("App delete failed on Approve process for Process Id: {0}", processId),
                      ex.StackTrace);
                    }
				}
				catch (Exception ex)
				{
					if (insightTransaction != null)
						insightTransaction.Rollback();

					if (rexTransaction != null && rexTransaction.Connection != null)
						rexTransaction.Rollback();

                    log.Error(string.Format("ProtocolProcess {0} failed Approval.", processId), ex);

					Utility.ExceptionReport.WriteToEventLog(String.Format("ProtocolProcess {0} failed Approval.", processId.ToString()),
						ex, true, Utility.ExceptionReport.ReportType.Error);

					return ex.Message;

				}
				finally
				{
					if (insightConnection.State != System.Data.ConnectionState.Closed)
						insightConnection.Close();

					if (rexConnection.State != System.Data.ConnectionState.Closed)
						rexConnection.Close();
				}
			}
			else
			{
				return String.Format("No process exists with ID: {0}", processId);
			}

			return "Success";
		}

		[WebMethod]
		public string NotifyIDSIS(string insightConnectionString)
		{
			try
			{
				// See if we have any information to send to the IDSIS team
				if (ConfigurationManager.AppSettings["EnableIDSISWebServiceCalls"].ToLower() == "true")
				{
					long resultCode;
					bool sendProtocolDataResult;
					// connect to db, read in rows, send transactions
					SqlConnection insightConnection = new SqlConnection(insightConnectionString);
					SqlCommand command = insightConnection.CreateCommand();
					command.CommandText = "GetIDSISProtocolUpdates";
					command.CommandType = CommandType.StoredProcedure;

					// Get the status changes first (notifications are for pending irb changes)
					command.Parameters.Add("@notifications", SqlDbType.Bit).Value = false;
					insightConnection.Open();
					SqlDataReader reader = command.ExecuteReader();
					log.Info("Starting send of protocols with changed status.");
					while (reader.Read())
					{
						Protocol protocol = new Protocol(new Policy.NullCachePolicy());
						protocol.Load(insightConnectionString, reader[0]);
						ProtocolVersion version = Protocol.GetLatestApplicationVersion(protocol.Id, insightConnectionString, false, new Policy.NullCachePolicy());
						if (version != null)
						{
							PushToIDSIS(protocol, version);
						}
					}
					reader.Close();
					log.Info("Finished send of protocols with changed status.");

					// Get the notifications
					command.Parameters[0].Value = true;
					reader = command.ExecuteReader();
					IDSIS.IDSRxWebServiceWse idsis = new global::InsightWebService.IDSIS.IDSRxWebServiceWse();
					SetIDSISWebServiceSecurity(ref idsis);
					log.Info("Starting send of pending change notifications.");
					while (reader.Read())
					{
						Protocol protocol = new Protocol(new Policy.NullCachePolicy());
						protocol.Load(insightConnectionString, reader[0]);
						ProtocolVersion version = Protocol.GetLatestApplicationVersion(protocol.Id, insightConnectionString, false, new Policy.NullCachePolicy());
						if (version != null && ProtocolMeetsIDSISCriteria(protocol, version))
						{
							log.Info(string.Format("Notify IDSIS started for protocol {0}", protocol.ProtocolNumber));
							IDSIS.ProtocolData protocolData = new global::InsightWebService.IDSIS.ProtocolData();
							protocolData.PendingAmendmentSpecified = true;
							protocolData.PendingAmendment = 1;
							protocolData.ProtocolNumber = protocol.ProtocolNumber;
							protocolData.PreviousPendingIRB = reader["PreviousPendingIRB"].ToString();
							protocolData.CurrentPendingIRB = reader["CurrentPendingIRB"].ToString();
							if (log.IsDebugEnabled)
							{
								IFormatter formatter = new SoapFormatter();
								MemoryStream ms = new MemoryStream();
								formatter.Serialize(ms, protocolData);
								log.Debug(Encoding.ASCII.GetString(ms.GetBuffer()));
							}
							idsis.SendProtocolData(protocolData, out resultCode, out sendProtocolDataResult);
							log.Info(string.Format("Notify IDSIS complete for protocol {0}, result code: {1}", protocol.ProtocolNumber, resultCode));
						}
					}
					insightConnection.Close();
					log.Info("Finished send of pending change notifications.");
				}
			}
			catch (Exception ex)
			{
				log.Error("Unhandled Exception in NotifyIDSIS method.", ex);
			}
			return "Success";
		}

		/// <summary>
		/// Notify IDSIS about the approved protocol / amendment
		/// Requirements: 
		///     New protocol or changed / amended protocol
		///     Completed D&B form or Yes to completed ancillary form
		///     Drug housed BWH IDS
		///     Ever Active
		/// </summary>
		/// <param name="protocol"></param>
		public void PushToIDSIS(PHSRAG.Insight21.Humans.Protocol protocol, PHSRAG.Insight21.Humans.ProtocolVersion version)
		{
			try
			{
				if (!ProtocolMeetsIDSISCriteria(protocol, version))
				{
					return;
				}
				log.Info(string.Format("Push to IDSIS started for protocol {0}", protocol.ProtocolNumber));
				ArrayList staffList = protocol.StudyStaffList;

				long resultCode;
				bool sendProtocolDataResult;

				IDSIS.IDSRxWebServiceWse idsis = new global::InsightWebService.IDSIS.IDSRxWebServiceWse();
				SetIDSISWebServiceSecurity(ref idsis);
				IDSIS.ProtocolData protocolData = new global::InsightWebService.IDSIS.ProtocolData();

				// Contacts
				ArrayList contacts = new ArrayList();
				foreach (StaffPerson staff in staffList)
				{
					IDSIS.Contact contact = new global::InsightWebService.IDSIS.Contact();
					contact.ContactRole = staff.Role;
					contact.ID = staff.Username;
					contact.Name = staff.FullName;
					contacts.Add(contact);
				}
				protocolData.Contacts = new global::InsightWebService.IDSIS.Contact[contacts.Count];
				contacts.CopyTo(protocolData.Contacts);

				// Drugs
				ArrayList drugs = new ArrayList();
				foreach (Forms.QuestionnaireAnswer qa in version.QuestionnaireAnswers)
				{
					if (qa.QuestionnaireVersion.Questionnaire.Name == "Drugs / Biologics / Dietary Supplements")
					{
						ArrayList dispenseLocations = qa.GetAnswers("DrugDispensed");
						foreach (Forms.Answer location in dispenseLocations)
						{
							// Housed at BWH IDSIS
							if (location.Value == "BWHPharm")
							{
								IDSIS.Drug drug = new global::InsightWebService.IDSIS.Drug();
								// Agent Formulations
								ArrayList formulations = new ArrayList();
								foreach (Forms.Answer answer in qa.GetAnswers("NumberUnits2"))
								{
									IDSIS.AgentFormulation formulation = new global::InsightWebService.IDSIS.AgentFormulation();
									formulation.Number = answer.Value;
									foreach (Forms.Answer childAnswer in answer.ChildAnswers)
									{
										switch (childAnswer.Name)
										{
											case "DrugFormulation":
												formulation.Form = childAnswer.Value;
												break;
											case "AgentUnits":
												formulation.Unit = childAnswer.Value;
												break;
										}
									}
									formulations.Add(formulation);
								}
								drug.AgentFormulations = new global::InsightWebService.IDSIS.AgentFormulation[formulations.Count];
								formulations.CopyTo(drug.AgentFormulations);

								drug.AgentType = qa.GetAnswerValue("TypeAgent2");
								drug.AgentUnderIND = qa.GetAnswerValue("StudiedUnderIND");
								drug.Antidotes = qa.GetAnswerValue("Antidotes");
								drug.DelayedSideEffects = qa.GetAnswerValue("DelayedSideEffects");

								// Doses
								ArrayList doses = new ArrayList();
								foreach (Forms.Answer answer in qa.GetAnswers("DoseNameInput"))
								{
									IDSIS.Dose dose = new global::InsightWebService.IDSIS.Dose();
									foreach (Forms.Answer childAnswer in answer.ChildAnswers)
									{
										switch (childAnswer.Name)
										{
											case "Dose":
												dose.Dose1 = childAnswer.Value;
												break;
											case "Route":
												dose.Route = childAnswer.Value;
												break;
											case "Frequency":
												dose.Frequency = childAnswer.Value;
												break;
											case "DurationAdmin":
												dose.Duration = childAnswer.Value;
												break;
										}
									}
									doses.Add(dose);
								}
								string doseItem = qa.GetAnswerValue("Dose2");
								if (!string.IsNullOrEmpty(doseItem))
								{
									IDSIS.Dose dose = new global::InsightWebService.IDSIS.Dose();
									dose.Dose1 = doseItem;
									dose.Route = qa.GetAnswerValue("Route2");
									dose.Frequency = qa.GetAnswerValue("Frequency2");
									dose.Duration = qa.GetAnswerValue("DurationAdmin2");
								}

								drug.Doses = new global::InsightWebService.IDSIS.Dose[doses.Count];
								doses.CopyTo(drug.Doses);

								drug.DrugName = qa.Name;
								drug.FDAStatus = qa.GetAnswerValue("FDAStatusDrug");
								drug.ImmediateSideEffects = qa.GetAnswerValue("ImmediateSideEffects");
								drug.Indication = qa.GetAnswerValue("IndicationforUseDrug");
								drug.IndicationComment = qa.GetAnswerValue("DrugExplainNonAppIndication") + qa.GetAnswerValue("DrugExplainAppIndication");
								drug.INDNumber = qa.GetAnswerValue("INDNumber");
								drug.INDNumberStatus = qa.GetAnswerValue("INDorPending");
								drug.INDSponsor = qa.GetAnswerValue("INDSponsor");
								drug.ScheduleIINarcotic = qa.GetAnswerValue("ScheduleII");
								drug.SpecialInstructions = qa.GetAnswerValue("SpecialInstruc");
								drug.SpecialMonitoringInstructions = qa.GetAnswerValue("SpecialMonitoring");

								// Storage requirements
								ArrayList storageReqs = new ArrayList();
								foreach (Forms.Answer storage in qa.GetAnswers("DrugStorageRequirements"))
								{
									storageReqs.Add(storage.Value);
								}
								string otherExplain = qa.GetAnswerValue("OtherExplain");
								if (!string.IsNullOrEmpty(otherExplain))
								{
									storageReqs.Add(otherExplain);
								}
								drug.StorageReqs = new string[storageReqs.Count];
								storageReqs.CopyTo(drug.StorageReqs);

								// Study Designs
								ArrayList studyDesigns = new ArrayList();
								foreach (Forms.Answer answer in qa.GetAnswers("StudyDesign"))
								{
									studyDesigns.Add(answer.Value);
								}
								drug.StudyDesigns = new string[studyDesigns.Count];
								studyDesigns.CopyTo(drug.StudyDesigns);

								drug.StudyPhase = qa.GetAnswerValue("StudyPhaseDesign");
								drugs.Add(drug);
								break;
							}
						}
					}
				}
				// Add Ancillary drugs
				if (ancillary != null)
				{
					foreach (Forms.Answer answer in ancillary.GetAnswers("AncillaryDrugName"))
					{
						IDSIS.Drug drug = new global::InsightWebService.IDSIS.Drug();
						drug.DrugName = answer.Value;
						drugs.Add(drug);
					}
				}
				protocolData.Drugs = new global::InsightWebService.IDSIS.Drug[drugs.Count];
				drugs.CopyTo(protocolData.Drugs);

				protocolData.EnrollmentNumber = studyPop.GetAnswerValue("PHSEnroll");
				ArrayList bwhFacilities = performanceSites.GetAnswers("BWHFacilities");
				protocolData.GCRCProtocol = "No";
				foreach (Forms.Answer answer in bwhFacilities)
				{
					if (answer.Value == "GCRC")
						protocolData.GCRCProtocol = "Yes";
				}

				protocolData.IRBApprovalDate = protocol.ApprovalDate;
				protocolData.IRBStatus = protocol.OverallStatus;

				// PI Departments
				ArrayList depts = new ArrayList();
				foreach (Forms.Answer answer in performanceSites.GetAnswers("SiteBWH"))
				{
					depts.Add(answer.Value);
				}
				protocolData.PIDepartments = new string[depts.Count];
				depts.CopyTo(protocolData.PIDepartments);

				protocolData.ProtocolNumber = protocol.ProtocolNumber;
				protocolData.Sponsor = protocol.SponsorName;
				protocolData.SponsorProtocolNumber = protocol.Version;
				protocolData.StudyTitle = protocol.Title;
				if (log.IsDebugEnabled)
				{
					IFormatter formatter = new SoapFormatter();
					MemoryStream ms = new MemoryStream();
					formatter.Serialize(ms, protocolData);
					log.Debug(Encoding.ASCII.GetString(ms.GetBuffer()));
				}
				idsis.SendProtocolData(protocolData, out resultCode, out sendProtocolDataResult);
				log.Info(string.Format("Push to IDSIS complete for protocol {0}, resultcode: {1}", protocol.ProtocolNumber, resultCode));
			}
			catch (Exception ex)
			{
				log.Error("Unhandled Exception in PushToIDSIS method.", ex);

				Utility.ExceptionReport.WriteToEventLog(String.Format("Failed to notify IDSIS web service for protocol {0}.", protocol.ProtocolNumber),
					ex, true, Utility.ExceptionReport.ReportType.Error);

				throw;
			}
		}

		/// <summary>
		/// Requirements: 
		///     New protocol or changed / amended protocol
		///     Completed D&B form or Yes to completed ancillary form
		///     Drug housed BWH IDS
		///     Ever Active
		/// </summary>
		/// <param name="protocol"></param>
		/// <param name="version"></param>
		/// <returns></returns>
		private bool ProtocolMeetsIDSISCriteria(Protocol protocol, ProtocolVersion version)
		{
			log.Debug(string.Format("Testing whether protocol {0} meets criteria.", protocol.ProtocolNumber));
			// Ever Active
			if (string.IsNullOrEmpty(protocol.ApprovalDate)
				|| protocol.OverallStatus == Constants.ProtocolOverallStatusText.Pending
				|| (protocol.OverallStatusId == InactiveOverallStatus
					&& protocol.SubStatusId == IRBWithdrawnSubStatus))
			{
				log.Debug(string.Format("Protocol doesn't meet \"Ever Active\" criteria."));
				return false;
			}

			bool idsisRelated = false;
			foreach (Forms.QuestionnaireAnswer qa in version.QuestionnaireAnswers)
			{
				// Check drug housed @ BWH IDS 
				if (qa.QuestionnaireVersion.Questionnaire.Name == "Drugs / Biologics / Dietary Supplements")
				{
					ArrayList dispenseLocations = qa.GetAnswers("DrugDispensed");
					foreach (Forms.Answer location in dispenseLocations)
					{
						// Housed at BWH IDSIS
						if (location.Value == "BWHPharm")
						{
							idsisRelated = true;
							break;
						}
					}
				}
				// yes to Ancillary
				if (qa.QuestionnaireVersion.Questionnaire.Name == "Ancillary Drugs")
				{
					if (qa.GetAnswerValue("AncillaryDrugs") == "Yes")
					{
						foreach (StaffPerson staff in protocol.StudyStaffList)
						{
							// If a PI is from BWH, send to IDSIS
							if ((staff.Role == "Principal Investigator" || staff.Role == "Site Responsible Investigator") && staff.InstitutionalName == "BWH")
							{
								idsisRelated = true;
								ancillary = qa;
								break;
							}
						}
					}
				}
				// Caching
				if (qa.Name == "Study Population")
				{
					studyPop = qa;
				}
				if (qa.Name == "Performance Sites / Facilities")
				{
					performanceSites = qa;
				}
			}
			if (!idsisRelated)
                log.Debug(string.Format("Protocol doesn't meet D&B / ancillary criteria."));

			return idsisRelated;
		}

		private void SetIDSISWebServiceSecurity(ref IDSIS.IDSRxWebServiceWse ws)
		{
			if (ConfigurationManager.AppSettings["EnableIDSISWebServiceSecurity"].ToLower() == "true")
			{
				//Create our UsernameToken and supply the consumer credentials...
				string username = ConfigurationManager.AppSettings["IDSISWebServiceUsername"];
				string password = ConfigurationManager.AppSettings["IDSISWebServicePassword"];
				Microsoft.Web.Services3.Design.UsernameTokenProvider user = new Microsoft.Web.Services3.Design.UsernameTokenProvider(username, password);
				//Create the policy assertion... 
				Microsoft.Web.Services3.Design.UsernameOverTransportAssertion assert = new Microsoft.Web.Services3.Design.UsernameOverTransportAssertion();
				assert.UsernameTokenProvider = user;
				assert.ServiceActor = @"http://partners.org/security/webservicesecurity";
				//Set the policy... 
				ws.SetPolicy(new Microsoft.Web.Services3.Design.Policy(assert));
			}
		}
	}
}
